<?php

namespace apiend\components;

use Yii;
use apiend\filters\AppBearerAuth;
use yii\web\NotFoundHttpException;
use yii\db\ActiveRecordInterface;

/**
 * Controller is the base class for RESTful API controller classes.
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class Controller extends \common\rest\Controller {

    /**
     * @var string|array the configuration for creating the serializer that formats the response data.
     */
    public $serializer = [
        'class' => 'common\rest\Serializer',
        'collectionEnvelope' => 'items',
        'metaEnvelope' => 'meta',
        'sortsEnvelope' => null,
        'linksEnvelope' => null,
    ];

    /**
     * @var array This Appliacation's Serializer Configures.
     */
    public $authenticator = [
        'class' => AppBearerAuth::class,
    ];

    /**
     * @inheritdoc
     */
    protected function rules() {
        return [
            [
                'allow' => true,
                'roles' => ['@'],
            ],
        ];
    }

    /**
     * @var string class name of the model which will be handled by this action.
     * The model class must implement [[ActiveRecordInterface]].
     * This property must be set.
     */
    public $modelClass;

    /**
     * @var callable a PHP callable that will be called to return the model corresponding
     * to the specified primary key value. If not set, [[findModel()]] will be used instead.
     * The signature of the callable should be:
     *
     * ```php
     * function ($id, $action) {
     *     // $id is the primary key value. If composite primary key, the key values
     *     // will be separated by comma.
     *     // $action is the action object currently running
     * }
     * ```
     *
     * The callable should return the model found, or throw an exception if not found.
     */
    public $findModel;

    /**
     * Returns the data model based on the primary key given.
     * If the data model is not found, a 404 HTTP exception will be raised.
     * @param string $id the ID of the model to be loaded. If the model has a composite primary key,
     * the ID must be a string of the primary key values separated by commas.
     * The order of the primary key values should follow that returned by the `primaryKey()` method
     * of the model.
     * @return ActiveRecordInterface the model found
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function findModel($id) {
        if ($this->findModel !== null) {
            return call_user_func($this->findModel, $id, $this);
        }
        if (!$this->modelClass) {
            throw new \yii\web\UnprocessableEntityHttpException("不支持的操作方式，数据模型不存在: $id");
        }
        /* @var $modelClass ActiveRecordInterface */
        $modelClass = $this->modelClass;
        $keys = $modelClass::primaryKey();
        if (count($keys) > 1) {
            $values = explode(',', $id);
            if (count($keys) === count($values)) {
                $model = $modelClass::findOne(array_combine($keys, $values));
            }
        } elseif ($id !== null) {
            $model = $modelClass::findOne($id);
        }
        if (!isset($model)) {
            throw new NotFoundHttpException("Object not found: $id");
        }
        return $model;
    }

}
